package info.touret.winecellar.producer.client;

import static info.touret.winecellar.dao.client.Constants.PAGE_SIZE;
import info.touret.winecellar.bottle.client.BottleRequest;
import info.touret.winecellar.bottle.shared.BottleProxy;
import info.touret.winecellar.producer.shared.ProducerProxy;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.activity.shared.Activity;
import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.cell.client.EditTextCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SelectionModel;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.web.bindery.requestfactory.shared.EntityProxyChange;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.ServerFailure;

public class ProducerListUI extends Composite implements
		EntityProxyChange.Handler<ProducerProxy>, Activity {
	private ProducerRequestFactory requestFactory;
	private static ProducerListUIUiBinder uiBinder = GWT
			.create(ProducerListUIUiBinder.class);

	@UiField
	CellTable<ProducerProxy> cellTable;

	@UiFactory
	CellTable<ProducerProxy> createCellTable() {
		CellTable.Resources resources = GWT.create(TableResources.class);
		return new CellTable<ProducerProxy>(20, resources);
	}

	interface ProducerListUIUiBinder extends UiBinder<Widget, ProducerListUI> {
	}

	interface TableResources extends CellTable.Resources {
		@Source({ CellTable.Style.DEFAULT_CSS, "ProducerListCellTable.css" })
		TableStyle cellTableStyle();
	}

	/**
	 * The styles applied to the table.
	 */
	interface TableStyle extends CellTable.Style {
	}

	public ProducerListUI() {
		initWidget(uiBinder.createAndBindUi(this));
	}

	/**
	 * Custom listener for this widget.
	 */
	interface Listener {

		/**
		 * Called when the user selects a report.
		 * 
		 * @param report
		 *            the selected report
		 */
		void onReportSelected(ProducerProxy producer);
	}

	public ProducerListUI(ProducerRequestFactory requestFactory) {
		this.requestFactory = requestFactory;
		initWidget(uiBinder.createAndBindUi(this));
		GWT.log("initialisation du tableau+++");
		showtable();
	}

	public ProducerRequestFactory getRequestFactory() {
		return requestFactory;
	}

	public void setRequestFactory(ProducerRequestFactory requestFactory) {
		this.requestFactory = requestFactory;
	}

	public void showtable() {
		try {
			GWT.log("creation du tableau...");
			createTable();
			GWT.log("Peuplement du tableau...");
			populateTable();
		} catch (Exception e) {
			GWT.log(e.getMessage(), e);
		}
	}

	private List<ProducerProxy> producers;

	public List<ProducerProxy> getProducers() {
		return producers;
	}

	public void setProducers(List<ProducerProxy> producers) {
		this.producers = producers;
	}

	@Override
	public String mayStop() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onCancel() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onStop() {
		running = false;

	}

	@SuppressWarnings("unused")
	private Boolean running;
	private List<ProducerProxy> selectedProducers;

	private static final ProvidesKey<ProducerProxy> KEY_PROVIDER = new ProvidesKey<ProducerProxy>() {
		public Object getKey(ProducerProxy item) {
			return item.getId();
		}
	};

	private void createTable() {
		// Attach a column sort handler to the ListDataProvider to sort the
		// list.

		// Add a selection model so we can select cells.
		final SelectionModel<ProducerProxy> selectionModel = new SingleSelectionModel<ProducerProxy>(
				KEY_PROVIDER);
		final SelectionModel<ProducerProxy> checkboxSelectionModel = new MultiSelectionModel<ProducerProxy>(
				KEY_PROVIDER);

		cellTable.setSelectionModel(checkboxSelectionModel,
				DefaultSelectionEventManager
						.<ProducerProxy> createCheckboxManager());

		Column<ProducerProxy, Boolean> checkColumn = new Column<ProducerProxy, Boolean>(
				new CheckboxCell(true, false)) {
			@Override
			public Boolean getValue(ProducerProxy object) {
				return checkboxSelectionModel.isSelected(object);
			}
		};
		cellTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant(""));
		// cellTable.setColumnWidth(checkColumn, 40, Unit.PX);

		final Receiver<Void> updateReceiver = new Receiver<Void>() {
			@Override
			public void onSuccess(Void response) {
				// rien
			}

			@Override
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
				Window.alert("La modification a echouee");
			}

		};

		// nom du producteur
		final EditTextCell nameCell = new EditTextCell();
		Column<ProducerProxy, String> nameColumn = new Column<ProducerProxy, String>(
				nameCell) {
			@Override
			public String getValue(ProducerProxy object) {
				return object.getName();
			}

		};
		// nameColumn.setSortable(true);
		nameColumn.setFieldUpdater(new FieldUpdater<ProducerProxy, String>() {
			@Override
			public void update(int index, ProducerProxy object, String value) {
				// nameCell.clearViewData(KEY_PROVIDER.getKey(object));

				ProducerRequest request = requestFactory.producerRequest();
				ProducerProxy proxy = request.edit(object);
				proxy.setName(value);
				request.update().using(proxy).fire(updateReceiver);
				return;
			}
		});

		cellTable.addColumn(nameColumn, "Nom");

		/* gestion du domaine */
		final EditTextCell domainCell = new EditTextCell();
		Column<ProducerProxy, String> domainColumn = new Column<ProducerProxy, String>(
				domainCell) {
			@Override
			public String getValue(ProducerProxy object) {
				String domain = object.getDomain();
				return domain == null ? "" : domain;
			}
		};

		domainColumn.setFieldUpdater(new FieldUpdater<ProducerProxy, String>() {
			@Override
			public void update(int index, ProducerProxy object, String value) {
				// nameCell.clearViewData(KEY_PROVIDER.getKey(object));

				ProducerRequest request = requestFactory.producerRequest();
				ProducerProxy proxy = request.edit(object);
				proxy.setDomain(value);
				request.update().using(proxy).fire(updateReceiver);
				return;
			}
		});
		// domainColumn.setSortable(true);
		cellTable.addColumn(domainColumn, "Domaine");

		/*
		 * Region
		 */

		final EditTextCell regionCell = new EditTextCell();
		Column<ProducerProxy, String> regionColumn = new Column<ProducerProxy, String>(
				regionCell) {
			@Override
			public String getValue(ProducerProxy object) {
				return object.getRegion();
			}
		};

		regionColumn.setFieldUpdater(new FieldUpdater<ProducerProxy, String>() {
			@Override
			public void update(int index, ProducerProxy object, String value) {
				// nameCell.clearViewData(KEY_PROVIDER.getKey(object));

				ProducerRequest request = requestFactory.producerRequest();
				ProducerProxy proxy = request.edit(object);
				proxy.setRegion(value);
				request.update().using(proxy).fire(updateReceiver);
				return;
			}
		});
		// regionColumn.setSortable(true);
		cellTable.addColumn(regionColumn, "Region");
		/**
		 * ville
		 * */
		final EditTextCell cityCell = new EditTextCell();
		Column<ProducerProxy, String> cityColumn = new Column<ProducerProxy, String>(
				cityCell) {
			@Override
			public String getValue(ProducerProxy object) {
				return object.getCity();
			}
		};

		cityColumn.setFieldUpdater(new FieldUpdater<ProducerProxy, String>() {
			@Override
			public void update(int index, ProducerProxy object, String value) {
				// nameCell.clearViewData(KEY_PROVIDER.getKey(object));

				ProducerRequest request = requestFactory.producerRequest();
				ProducerProxy proxy = request.edit(object);
				proxy.setCity(value);
				request.update().using(proxy).fire(updateReceiver);
				return;
			}
		});

		cellTable.addColumn(cityColumn, "Ville");
		/*
		 * ZIP
		 */
		final EditTextCell zipCell = new EditTextCell();
		Column<ProducerProxy, String> zipColumn = new Column<ProducerProxy, String>(
				zipCell) {
			@Override
			public String getValue(ProducerProxy object) {
				return object.getZip();
			}
		};

		zipColumn.setFieldUpdater(new FieldUpdater<ProducerProxy, String>() {
			@Override
			public void update(int index, ProducerProxy object, String value) {
				// nameCell.clearViewData(KEY_PROVIDER.getKey(object));

				ProducerRequest request = requestFactory.producerRequest();
				ProducerProxy proxy = request.edit(object);
				proxy.setZip(value);
				request.update().using(proxy).fire(updateReceiver);
				return;
			}
		});

		cellTable.addColumn(zipColumn, "CP");

		/*
		 * Telephone
		 */

		final EditTextCell phoneCell = new EditTextCell();
		Column<ProducerProxy, String> phoneColumn = new Column<ProducerProxy, String>(
				phoneCell) {
			@Override
			public String getValue(ProducerProxy object) {
				return object.getPhone();
			}
		};
		phoneColumn.setFieldUpdater(new FieldUpdater<ProducerProxy, String>() {
			@Override
			public void update(int index, ProducerProxy object, String value) {
				// nameCell.clearViewData(KEY_PROVIDER.getKey(object));

				ProducerRequest request = requestFactory.producerRequest();
				ProducerProxy proxy = request.edit(object);
				proxy.setPhone(value);
				request.update().using(proxy).fire(updateReceiver);
				return;
			}
		});
		cellTable.addColumn(phoneColumn, "Telephone");

		final TextCell testcell = new TextCell();
		Column<ProducerProxy, String> testC = new Column<ProducerProxy, String>(
				testcell) {
			@Override
			public String getValue(ProducerProxy object) {
				return "";
			}
		};
		cellTable.addColumn(testC, "");
		cellTable.setColumnWidth(testC, 300, Unit.PX);

		//

		pager.setPageSize(PAGE_SIZE);
		pager.setDisplay(cellTable);
	}

	private Receiver<List<ProducerProxy>> lastDataReceiver;
	private List<ProducerProxy> lastData;

	private ProducerRequest getRequest() {
		return getRequestFactory().producerRequest();
	}

	private Request<List<ProducerProxy>> getProducers(String criteria) {
		Request<List<ProducerProxy>> producers = null;
		if (criteria == null || criteria.length() == 0) {
			producers = getRequest().findAllProducers();
		} else {
			producers = getRequest().findProducersByCriteria(criteria);
		}
		return producers;
	}

	private void populateTable() {
		AsyncDataProvider<ProducerProxy> dataProdiver = new AsyncDataProvider<ProducerProxy>() {
			@Override
			protected void onRangeChanged(HasData<ProducerProxy> display) {
				final int start = display.getVisibleRange().getStart();
				final int displayLength = display.getVisibleRange().getLength();
				final Request<List<ProducerProxy>> getReq = getProducers(searchbox
						.getValue());
				lastDataReceiver = new Receiver<List<ProducerProxy>>() {
					@Override
					public void onSuccess(List<ProducerProxy> response) {
						int end = start + displayLength;
						if (start + PAGE_SIZE > response.size()) {
							end = response.size();
						}
						cellTable.setVisibleRange(start, end);
						updateRowCount(response.size(), true);
						updateRowData(start, response.subList(start, end));
						lastData = new ArrayList<ProducerProxy>(
								response.subList(start, end));
					}

					@Override
					public void onFailure(ServerFailure error) {
						super.onFailure(error);
					}
				};
				getReq.fire(lastDataReceiver);
			}
		};
		dataProdiver.addDataDisplay(cellTable);
	}

	@UiField(provided = true)
	SimplePager pager = new SimplePager(TextLocation.CENTER);
	@UiField
	Button deleteButton;
	@UiField
	Button updatebutton;

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.google.gwt.activity.shared.Activity#start(com.google.gwt.user.client
	 * .ui.AcceptsOneWidget, com.google.gwt.event.shared.EventBus)
	 */
	@Override
	public void start(AcceptsOneWidget panel, EventBus eventBus) {
		EntityProxyChange.registerForProxyType(eventBus, ProducerProxy.class,
				this);
		running = true;
		panel.setWidget(this);
	}

	@Override
	public void onProxyChange(EntityProxyChange<ProducerProxy> event) {
		// TODO Auto-generated method stub

	}

	@UiHandler("deleteButton")
	void onDeleteButtonClick(ClickEvent event) {
		deleteSelectedItems();
	}

	private void deleteSelectedItems() {
		if (lastDataReceiver != null) {
			final ProducerRequest req = getRequest();
			for (ProducerProxy current : lastData)
				if (cellTable.getSelectionModel().isSelected(current)) {
					ProducerProxy toremove = req.edit(current);
					req.remove().using(toremove);
				}
			req.fire(new Receiver<Void>() {
				@Override
				public void onSuccess(Void response) {
					populateTable();
				}
			});
		}
	}

	@UiHandler("updatebutton")
	void onUpdatebuttonClick(ClickEvent event) {
		populateTable();
	}

	@UiHandler("deleteButton1")
	void onDeleteButton1Click(ClickEvent event) {
		deleteSelectedItems();
	}

	@UiHandler("updatebutton1")
	void onUpdatebutton1Click(ClickEvent event) {
		populateTable();
	}

	interface SelectionStyle extends CssResource {
		String selectedRow();
	}

	@UiHandler("searchbutton")
	void onSearchbuttonClick(ClickEvent event) {
		final String criteria = searchbox.getValue();
		populateTable();
	}

	@UiField
	Button searchbutton;

	@UiField
	SuggestBox searchbox;

	MultiWordSuggestOracle suggestOracle;

	Receiver<List<ProducerProxy>> suggestboxreceiver;

	@UiFactory
	SuggestBox createSearchbox() {
		suggestOracle = new MultiWordSuggestOracle();
		SuggestBox box = new SuggestBox(suggestOracle);

		box.getTextBox().addKeyPressHandler(new KeyPressHandler() {

			@Override
			public void onKeyPress(KeyPressEvent arg0) {

				if (searchbox.getValue().length() > 2) {
					final String criteria = searchbox.getValue();
					ProducerRequest request = getRequest();
					Request<List<ProducerProxy>> getReq = request
							.findProducersByCriteria(criteria);
					suggestboxreceiver = new Receiver<List<ProducerProxy>>() {
						@Override
						public void onSuccess(List<ProducerProxy> response) {
							for (ProducerProxy current : response) {
								suggestOracle.add(current.getName());
							}
							searchbox.showSuggestionList();
						}
						@Override
						public void onFailure(ServerFailure error) {
							super.onFailure(error);
							Window.alert("Une erreur est survenue :-(");
						}
					};
					getReq.fire(suggestboxreceiver);
				}
			}
		});
		return box;
	}
}
